<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>7-js 对象</title>
  </head>
  <body>
    <h4>7-js 对象</h4>
    <p>简单的理解就是：把一堆数据和方法封装在一起，就形成了对象。</p>
    <script>
      /*
              1.对象的声明
              2.对象的调用
              3.对象的遍历
              4.对象的方法
              5.对象的属性
              6.对象的构造函数
              7.对象的原型
              8.对象的继承
            */

      // 对象的声明
      var obj = {
        // 对象的结构是键值对   键：值
        name: "张三",
        age: 18,
        sex: "男",
        sayHi: function () {
          console.log("60，对象的方法");
        },
      };
      console.log(obj);
      // 对象的调用
      console.log(obj.name);
      // 对象的遍历
      for (var key in obj) {
        console.log(key); // 键
        console.log(obj[key]); // 值
      }

      // 控制台换行
      console.log("");

      // 对象的方法
      obj.sayHi(); // 调用对象的方法

      // 面试题：对象有哪些方法？
      function fn() {
        // 答案：
        // 构造函数方法
        // Object.create()：用于创建一个新对象，使用现有的对象来提供新创建对象的__proto__。例如：
        const personProto = {
          greet() {
            console.log(`Hello!`);
          },
        };
        const newPerson = Object.create(personProto);
        newPerson.greet();

        // 属性访问方法
        // Object.keys()：返回一个由给定对象的自身可枚举属性的键名组成的数组。例如：
        const myObject = { a: 1, b: 2, c: 3 };
        const keys = Object.keys(myObject);
        console.log(keys); // ["a", "b", "c"]

        // Object.values()：返回一个由给定对象的自身可枚举属性的值组成的数组。例如：
        const myObject2 = { a: 1, b: 2, c: 3 };
        const values = Object.values(myObject2);
        console.log(values); // [1, 2, 3]

        // Object.entries()：返回一个给定对象自身可枚举属性的键 - 值对数组。例如：
        const myObject3 = { a: 1, b: 2, c: 3 };
        const entries = Object.entries(myObject3);
        console.log(entries); // [["a", 1], ["b", 2], ["c", 3]]

        // 对象操作方法
        // Object.assign()：用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。例如：
        const target = { a: 1, b: 2 };
        const source = { b: 3, c: 4 };
        const result = Object.assign(target, source);
        console.log(target); // {a: 1, b: 3, c: 4}
        console.log(result); // {a: 1, b: 3, c: 4}

        // 检测方法
        // Object.prototype.hasOwnProperty()：用于判断对象自身属性中是否具有指定的属性（会忽略从原型链上继承的属性）。例如：
        const myObject4 = { a: 1 };
        console.log(myObject4.hasOwnProperty("a")); // true
        console.log(myObject4.hasOwnProperty("toString")); // false
      }
      fn();

      // 6.对象的构造函数
      function fn2() {
        // 定义构造函数
        // 构造函数的命名通常采用大写字母开头的惯例（这不是强制要求，但可以帮助区分构造函数和普通函数）。例如，定义一个表示人的构造函数：
        function Person(name, age) {
          this.name = name;
          this.age = age;
          this.sayHello = function () {
            console.log(
              `Hello, my name is ${this.name} and I'm ${this.age} years old.`
            );
          };
        }
        // 上述代码中，Person是一个构造函数，它接受name和age两个参数。在构造函数内部，通过this关键字将参数赋值给对象的属性name和age，并且定义了一个方法sayHello。

        // 创建对象实例
        // 一旦定义了构造函数，就可以使用new关键字来创建对象实例。例如：
        const person1 = new Person("Alice", 30);
        const person2 = new Person("Bob", 35);
        console.log(person1);
        console.log(person2);

        // 构造函数的原型（prototype）
        // JavaScript 中的每个函数都有一个prototype属性，这个属性是一个对象，它包含了可以被该函数的所有实例共享的属性和方法。通过在构造函数的原型上添加方法，可以减少内存占用，因为所有实例都可以共享这些方法。例如：
        function Person(name, age) {
          this.name = name;
          this.age = age;
        }
        Person.prototype.sayHello = function () {
          console.log(
            `Hello, my name is ${this.name} and I'm ${this.age} years old.`
          );
        };
        let person3 = new Person("Alice", 30);
        let person4 = new Person("Bob", 25);
        console.log(person3);
        console.log(person4);
      }
      fn2();
      // 7.对象的原型
      function fn3() {
        // 定义构造函数
        function Person(name, age) {
          this.name = name;
          this.age = age;
        }
        // 给构造函数的原型添加方法
        Person.prototype.sayHello = function () {
          console.log(
            `Hello, my name is ${this.name} and I'm ${this.age} years old.`
          );
        };
        let person5 = new Person("Alice", 30);
        let person6 = new Person("Bob", 25);
        console.log(person5);
        console.log(person6);
      }
      fn3();
      // 8.对象的继承
      function fn4() {
        // 定义父类
        function Animal(name) {
          this.name = name;
        }
        Animal.prototype.sayHello = function () {
          console.log(`Hello, my name is ${this.name}.`);
        };
        // 定义子类
        function Dog(name, breed) {
          Animal.call(this, name);
          this.breed = breed;
        }
        // 实现子类与父类的继承关系
        Dog.prototype = Object.create(Animal.prototype);
        Dog.prototype.constructor = Dog;
        let dog1 = new Dog("Buddy", "Golden Retriever");
        let dog2 = new Dog("Max", "Labrador Retriever");
        console.log(dog1); // Dog { name: "Buddy", breed: "Golden Retriever" }
        console.log(dog2); // Dog { name: "Max", breed: "Labrador Retriever" }
      }
      fn4();
    </script>
  </body>
</html>
